package com.mini.grpc.protoc;

import com.mini.grpc.protoc.generator.StubGenerator;
import com.mini.grpc.protoc.model.ServiceDefinition;
import com.mini.grpc.protoc.parser.ServiceParser;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Logger;

/**
 * Mini-gRPC代码生成工具主入口
 * 命令行工具，用于生成gRPC服务的Java代码
 * 
 * @author Mini-gRPC
 */
public class MiniGrpcProtocMain {
    
    private static final Logger logger = Logger.getLogger(MiniGrpcProtocMain.class.getName());
    
    private static final String USAGE = 
            "Usage: mini-grpc-protoc [OPTIONS]\n" +
            "Options:\n" +
            "  --proto_path=PATH, -I PATH    Specify the directory in which to search for imports\n" +
            "  --java_out=OUT_DIR           Generate Java source files\n" +
            "  --mini_grpc_out=OUT_DIR      Generate Mini-gRPC Java source files\n" +
            "  --input=INPUT_FILE           Input proto file or service definition\n" +
            "  --service_name=NAME          Service name (for simple generation)\n" +
            "  --package_name=NAME          Package name (for simple generation)\n" +
            "  --help, -h                   Show this help message\n" +
            "  --version, -v                Show version information\n" +
            "\n" +
            "Examples:\n" +
            "  mini-grpc-protoc --input=hello.proto --mini_grpc_out=src/main/java\n" +
            "  mini-grpc-protoc --service_name=Greeter --package_name=com.example --mini_grpc_out=src/main/java\n";
    
    private static final String VERSION = "Mini-gRPC Protoc Plugin 1.0.0";
    
    /**
     * 主入口方法
     * 
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        try {
            if (args.length == 0) {
                printUsage();
                System.exit(1);
            }
            
            CommandLineOptions options = parseCommandLine(args);
            
            if (options.isHelp()) {
                printUsage();
                System.exit(0);
            }
            
            if (options.isVersion()) {
                printVersion();
                System.exit(0);
            }
            
            validateOptions(options);
            generateCode(options);
            
            logger.info("代码生成完成");
            
        } catch (Exception e) {
            logger.severe("代码生成失败: " + e.getMessage());
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    /**
     * 解析命令行参数
     * 
     * @param args 命令行参数
     * @return 解析后的选项
     */
    private static CommandLineOptions parseCommandLine(String[] args) {
        CommandLineOptions options = new CommandLineOptions();
        
        for (String arg : args) {
            if (arg.equals("--help") || arg.equals("-h")) {
                options.setHelp(true);
            } else if (arg.equals("--version") || arg.equals("-v")) {
                options.setVersion(true);
            } else if (arg.startsWith("--proto_path=") || arg.startsWith("-I")) {
                String path = extractValue(arg, "--proto_path=", "-I");
                options.setProtoPath(path);
            } else if (arg.startsWith("--java_out=")) {
                String path = extractValue(arg, "--java_out=", null);
                options.setJavaOut(path);
            } else if (arg.startsWith("--mini_grpc_out=")) {
                String path = extractValue(arg, "--mini_grpc_out=", null);
                options.setMiniGrpcOut(path);
            } else if (arg.startsWith("--input=")) {
                String input = extractValue(arg, "--input=", null);
                options.setInputFile(input);
            } else if (arg.startsWith("--service_name=")) {
                String serviceName = extractValue(arg, "--service_name=", null);
                options.setServiceName(serviceName);
            } else if (arg.startsWith("--package_name=")) {
                String packageName = extractValue(arg, "--package_name=", null);
                options.setPackageName(packageName);
            } else {
                throw new IllegalArgumentException("未知参数: " + arg);
            }
        }
        
        return options;
    }
    
    /**
     * 提取参数值
     * 
     * @param arg 参数字符串
     * @param longPrefix 长前缀
     * @param shortPrefix 短前缀
     * @return 参数值
     */
    private static String extractValue(String arg, String longPrefix, String shortPrefix) {
        if (arg.startsWith(longPrefix)) {
            return arg.substring(longPrefix.length());
        } else if (shortPrefix != null && arg.startsWith(shortPrefix)) {
            return arg.substring(shortPrefix.length());
        }
        throw new IllegalArgumentException("无效参数格式: " + arg);
    }
    
    /**
     * 验证选项
     * 
     * @param options 命令行选项
     */
    private static void validateOptions(CommandLineOptions options) {
        if (options.getMiniGrpcOut() == null) {
            throw new IllegalArgumentException("必须指定 --mini_grpc_out 参数");
        }
        
        if (options.getInputFile() == null && options.getServiceName() == null) {
            throw new IllegalArgumentException("必须指定 --input 或 --service_name 参数");
        }
        
        if (options.getServiceName() != null && options.getPackageName() == null) {
            throw new IllegalArgumentException("使用 --service_name 时必须指定 --package_name");
        }
    }
    
    /**
     * 生成代码
     * 
     * @param options 命令行选项
     * @throws IOException 如果生成失败
     */
    private static void generateCode(CommandLineOptions options) throws IOException {
        ServiceParser parser = new ServiceParser();
        StubGenerator generator = new StubGenerator();
        
        List<ServiceDefinition> services;
        
        if (options.getInputFile() != null) {
            // 从文件解析
            Path inputPath = Paths.get(options.getInputFile());
            if (!Files.exists(inputPath)) {
                throw new FileNotFoundException("输入文件不存在: " + options.getInputFile());
            }
            
            try (InputStream inputStream = Files.newInputStream(inputPath)) {
                services = parser.parseFromInputStream(inputStream);
            }
        } else {
            // 简单生成模式
            ServiceDefinition service = parser.createSimpleService(
                    options.getServiceName(), options.getPackageName());
            services = Arrays.asList(service);
        }
        
        if (services.isEmpty()) {
            logger.warning("没有找到服务定义");
            return;
        }
        
        // 生成代码
        for (ServiceDefinition service : services) {
            generateServiceCode(service, options, generator);
        }
    }
    
    /**
     * 生成服务代码
     * 
     * @param service 服务定义
     * @param options 命令行选项
     * @param generator 代码生成器
     * @throws IOException 如果生成失败
     */
    private static void generateServiceCode(ServiceDefinition service, 
                                          CommandLineOptions options,
                                          StubGenerator generator) throws IOException {
        
        // 确定输出目录
        Path outputDir = Paths.get(options.getMiniGrpcOut());
        
        // 创建包目录
        if (service.getJavaPackage() != null) {
            String[] packageParts = service.getJavaPackage().split("\\.");
            for (String part : packageParts) {
                outputDir = outputDir.resolve(part);
            }
        }
        
        Files.createDirectories(outputDir);
        
        // 生成文件
        String fileName = service.getJavaClassName() + ".java";
        Path outputFile = outputDir.resolve(fileName);
        
        logger.info("生成文件: " + outputFile);
        
        try (Writer writer = Files.newBufferedWriter(outputFile)) {
            generator.generateStub(service, writer);
        }
    }
    
    /**
     * 打印使用说明
     */
    private static void printUsage() {
        System.out.println(USAGE);
    }
    
    /**
     * 打印版本信息
     */
    private static void printVersion() {
        System.out.println(VERSION);
    }
    
    /**
     * 命令行选项类
     */
    private static class CommandLineOptions {
        private boolean help = false;
        private boolean version = false;
        private String protoPath;
        private String javaOut;
        private String miniGrpcOut;
        private String inputFile;
        private String serviceName;
        private String packageName;
        
        // Getters and Setters
        public boolean isHelp() {
            return help;
        }
        
        public void setHelp(boolean help) {
            this.help = help;
        }
        
        public boolean isVersion() {
            return version;
        }
        
        public void setVersion(boolean version) {
            this.version = version;
        }
        
        public String getProtoPath() {
            return protoPath;
        }
        
        public void setProtoPath(String protoPath) {
            this.protoPath = protoPath;
        }
        
        public String getJavaOut() {
            return javaOut;
        }
        
        public void setJavaOut(String javaOut) {
            this.javaOut = javaOut;
        }
        
        public String getMiniGrpcOut() {
            return miniGrpcOut;
        }
        
        public void setMiniGrpcOut(String miniGrpcOut) {
            this.miniGrpcOut = miniGrpcOut;
        }
        
        public String getInputFile() {
            return inputFile;
        }
        
        public void setInputFile(String inputFile) {
            this.inputFile = inputFile;
        }
        
        public String getServiceName() {
            return serviceName;
        }
        
        public void setServiceName(String serviceName) {
            this.serviceName = serviceName;
        }
        
        public String getPackageName() {
            return packageName;
        }
        
        public void setPackageName(String packageName) {
            this.packageName = packageName;
        }
    }
} 